package com.amigo.online.provider.merchant.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.bson.Document;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSONObject;
import com.amigo.online.common.base.service.BaseService;
import com.amigo.online.common.core.response.Response;
import com.amigo.online.common.core.response.StatusCode;
import com.amigo.online.common.param.RedisKey;
import com.amigo.online.common.param.common.KeyValueModel;
import com.amigo.online.common.param.dto.merchant.EditBasicMerchantDto;
import com.amigo.online.common.param.dto.merchant.MerchantApplyDto;
import com.amigo.online.common.param.dto.merchant.MerchantAvatarDto;
import com.amigo.online.common.param.dto.merchant.MerchantEnvironmentDto;
import com.amigo.online.common.param.result.UserInfo;
import com.amigo.online.common.param.result.adv.ProvinceAndCity;
import com.amigo.online.common.param.result.goods.GoodsImgInfo;
import com.amigo.online.common.param.result.goods.HomeGoodsInfo;
import com.amigo.online.common.param.result.goods.MerchantGoodsInfo;
import com.amigo.online.common.param.result.merchant.CollectGoodsInfo;
import com.amigo.online.common.param.result.merchant.MerchantConcernListInfo;
import com.amigo.online.common.param.result.merchant.MerchantDetailInfo;
import com.amigo.online.common.param.result.merchant.MerchantHomeInfo;
import com.amigo.online.provider.merchant.common.ConstantValue;
import com.amigo.online.provider.merchant.common.GlobalController;
import com.amigo.online.provider.merchant.common.RwRedisService;
import com.amigo.online.provider.merchant.exception.MerchantException;
import com.amigo.online.provider.merchant.mapper.CategoryMapper;
import com.amigo.online.provider.merchant.mapper.GoodsCommentMapper;
import com.amigo.online.provider.merchant.mapper.GoodsImgMapper;
import com.amigo.online.provider.merchant.mapper.GoodsMapper;
import com.amigo.online.provider.merchant.mapper.MerchantAdvMapper;
import com.amigo.online.provider.merchant.mapper.MerchantConcernMapper;
import com.amigo.online.provider.merchant.mapper.MerchantEnvironmentMapper;
import com.amigo.online.provider.merchant.mapper.MerchantMapper;
import com.amigo.online.provider.merchant.model.entity.Category;
import com.amigo.online.provider.merchant.model.entity.Goods;
import com.amigo.online.provider.merchant.model.entity.GoodsImg;
import com.amigo.online.provider.merchant.model.entity.Merchant;
import com.amigo.online.provider.merchant.model.entity.MerchantAdv;
import com.amigo.online.provider.merchant.model.entity.MerchantConcern;
import com.amigo.online.provider.merchant.model.entity.MerchantEnvironment;
import com.amigo.online.provider.merchant.mongo.dao.MerchantDao;
import com.amigo.online.provider.merchant.service.AreaFeignService;
import com.amigo.online.provider.merchant.service.MerchantService;
import com.amigo.online.provider.merchant.service.UserFeignService;
import com.amigo.online.provider.merchant.utils.ConvertUtil;
import com.amigo.online.provider.merchant.utils.LanguageEnum;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mongodb.BasicDBObject;
import com.mongodb.client.AggregateIterable;
import com.mongodb.client.MongoCursor;

/**
 * <code>MerchantServiceImpl.java</code>
 * <p>
 * : 商家服务
 * </p>
 * <p>
 *
 * @author LuChen
 * @version 1.0
 * @company Amigo
 * @time 2018年12月15日 下午3:34:13
 * @lastUpdate 无
 * </p>
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class MerchantServiceImpl extends BaseService<Merchant> implements MerchantService {

    @Autowired
    private MerchantConcernMapper merchantConcernMapper;

    @Autowired
    private MerchantMapper merchantMapper;

    @Autowired
    private GoodsMapper goodsMapper;

    @Autowired
    private MerchantAdvMapper merchantAdvMapper;

    @Autowired
    private CategoryMapper categoryMapper;

    @Autowired
    private RwRedisService redisService;

    @Autowired
    private MerchantEnvironmentMapper merchantEnvironmentMapper;

    @Autowired
    private AreaFeignService areaFeignService;

    @Autowired
    private GoodsImgMapper goodsImgMapper;

    @Autowired
    private GoodsCommentMapper goodsCommentMapper;

    @Autowired
    private UserFeignService userFeignService;

    @Autowired
    private MerchantDao merchantDao;

    @Override
    public Integer getConcernCount(Long merId) {
        Integer count = (Integer) redisService.get(RedisKey.MERCHANT_CONCERN_KEY + merId);
        if (count == null) {
            count = merchantConcernMapper.getConcernCount(merId);
            redisService.set(RedisKey.MERCHANT_CONCERN_KEY + merId, count);
        }
        return count;
    }

    @Override
    public boolean concernMerchantById(Long merId) {
        UserInfo user = GlobalController.getNowUser();
        Long userId = user.getId();
        MerchantConcern mc = new MerchantConcern();
        mc.setMerchantId(merId);
        mc.setUserId(userId);
        mc.setDeleted(0);
        if (merchantConcernMapper.select(mc).size() <= 0) {
            mc.setCreatedTime(System.currentTimeMillis() / 1000);
            merchantConcernMapper.insert(mc);
        }
        redisService.delete(RedisKey.MERCHANT_CONCERN_KEY + merId);
        return true;
    }

    @Override
    public boolean cancelConcernMerchantById(Long merId) {
        UserInfo user = GlobalController.getNowUser();
        Long userId = user.getId();
        Long nowTime = System.currentTimeMillis() / 1000;
        merchantConcernMapper.updateDeleted(userId, merId, nowTime);
        redisService.delete(RedisKey.MERCHANT_CONCERN_KEY + merId);
        return true;
    }

    @Override
    public MerchantConcernListInfo getConcernMerList(Integer page, Integer size) {
        UserInfo user = GlobalController.getNowUser();
        page = GlobalController.checkPage(page, size);
        Long userId = user.getId();
        List<Merchant> list = merchantMapper.getConcernList(userId, (page - 1) * size, size);
        List<Integer> listCounts = merchantMapper.getCounts(userId);
        MerchantConcernListInfo info = ConvertUtil.merTomerInfo(list);
        info.setCount(listCounts);
        return info;
    }

    @Override
    public List<CollectGoodsInfo> getCollectMerList(Integer page, Integer size) {
        UserInfo user = GlobalController.getNowUser();
        page = GlobalController.checkPage(page, size);
        Long userId = user.getId();
        List<Goods> list = goodsMapper.getMerchantCollectList(userId, (page - 1) * size, size);
        List<CollectGoodsInfo> info = ConvertUtil.goodsToMerCollectInfo(list);
        return info;
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<MerchantAdv> getHomePageAdv() {
        List<MerchantAdv> merchantAdvList = redisService.opsForListRead().range(RedisKey.MERCHANT_ADV_KEY, 0, -1);
        if (merchantAdvList == null || merchantAdvList.isEmpty()) {
            merchantAdvList = merchantAdvMapper.getAdv();
            if (merchantAdvList != null && !merchantAdvList.isEmpty()) {
                redisService.opsForList().rightPushAll(RedisKey.MERCHANT_ADV_KEY, merchantAdvList);
            }
        }
        return merchantAdvList;
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<Category> getHomePageCategory() {
        List<Category> categoryAdvList = redisService.opsForListRead().range(RedisKey.MERCHANT_HOME_PAGE_CATEGORY_KEY,
                0, -1);
        if (categoryAdvList == null || categoryAdvList.isEmpty()) {
            categoryAdvList = categoryMapper.getHomePageCategory();
            if (categoryAdvList != null && categoryAdvList.size() == 0) {
                redisService.opsForList().rightPushAll(RedisKey.MERCHANT_HOME_PAGE_CATEGORY_KEY, categoryAdvList);
            }
        }
        return categoryAdvList;
    }

    @Override
    public JSONObject getMerchantHome(Long merchantId, Integer page, Integer size, String language) {
        language = LanguageEnum.getColumnName(language);
        page = GlobalController.checkPage(page, size);
        Integer start = (page - 1) * size;
        MerchantHomeInfo homeInfo = merchantMapper.getMerchantHome(merchantId, language);
        if (homeInfo != null) {
            homeInfo.setConcernNum(getConcernCount(merchantId)); // 店铺关注人数
            int count = merchantMapper.getCountByMerchantIdAndUserId(merchantId, GlobalController.getNowUser().getId());
            homeInfo.setConcerned(count > 0); // 是否关注了店铺
            ProvinceAndCity provinceAndCity = getProvinceAndCity(language, homeInfo.getStoreAreaId());
            homeInfo.setProvince(provinceAndCity != null ? provinceAndCity.getProvince() : "");
            homeInfo.setCity(provinceAndCity != null ? provinceAndCity.getCity() : "");
            homeInfo.getCategoryId();
            List<KeyValueModel<Long, String>> categoryList = merchantMapper.getCategoryByMerchantId(merchantId,
                    language);
            //在类别添加一个"全部"类别
            if (categoryList.size() > 0) {
                KeyValueModel<Long, String> model = new KeyValueModel<>();
                model.setId(0L);
                model.setValue(StatusCode.ALL.msg());
                categoryList.add(0, model);
            }
            homeInfo.setCategory(categoryList);
        }
        // type 查询类别 ,1热门 2推荐 3好评率
        List<HomeGoodsInfo> homegoodsInfos = goodsMapper.getGoodsOrderBYField(merchantId, start, size, 1, null);
        JSONObject rs = new JSONObject();
        rs.put("merchant", homeInfo);
        rs.put("goods", homegoodsInfos);
        rs.put("user", getStoreKeeperInfo(merchantId));
        return rs;

    }

    private JSONObject getStoreKeeperInfo(Long merchantId) {
        Merchant merchant = merchantMapper.selectByPrimaryKey(merchantId);
        if (merchant == null)
            return new JSONObject();
        Object response = userFeignService.getUserInfo(merchant.getUserId()).getBody().getData();
        ObjectMapper mapper = new ObjectMapper();
        UserInfo userInfo = mapper.convertValue(response, UserInfo.class);
        JSONObject user = new JSONObject();
        if (userInfo != null) {
            user.put("id", userInfo.getId());
            user.put("avatar", userInfo.getAvatar());
            user.put("avatarSamll", userInfo.getAvatarSmall());
            user.put("nickname", userInfo.getNickname());
        }
        return user;
    }

    @Override
    public MerchantHomeInfo applyOpenMerchant(MerchantApplyDto dto, String language) {
        MerchantHomeInfo homeInfo = null;
        try {
            UserInfo localUser = GlobalController.getNowUser();
            if (merchantMapper.checkMerchantKeeper(localUser.getId()) > 0) {
                throw new MerchantException(StatusCode.CAN_ONLY_HAS_ONE_MERCHANT);
            }
            Merchant merchant = new Merchant();
            merchant.setUserId(localUser.getId());
            merchant.setCreatedTime(System.currentTimeMillis() / 1000);
            BeanUtils.copyProperties(dto, merchant);
            merchant.setGrade(0d);//默认评分0
            merchantMapper.insertSelective(merchant);
            homeInfo = merchantMapper.getMerchantHomeByUserId(localUser.getId(), language, 1);
            if (homeInfo != null) {
                ProvinceAndCity provinceAndCity = getProvinceAndCity(language, homeInfo.getStoreAreaId());
                homeInfo.setProvince(provinceAndCity != null ? provinceAndCity.getProvince() : "");
                homeInfo.setCity(provinceAndCity != null ? provinceAndCity.getCity() : "");
            }
            // 提交成功后修改用户店铺状态缓存
            String merchant_status_key = RedisKey.MERCHANT_STATUS_KEY + localUser.getId();
            redisService.delete(merchant_status_key);
        } catch (BeansException e) {
            logger.error("发生了异常");
            e.printStackTrace();
        }
        logger.info("没有异常，数据库已插入");
        return homeInfo;
    }

    private ProvinceAndCity getProvinceAndCity(String language, Long areaId) {
        ResponseEntity<Response> rs = areaFeignService.getProvinceAndCityByCityId(areaId,
                language == null ? "name_pt" : language);
        ObjectMapper mapper = new ObjectMapper();
        ProvinceAndCity provinceAndCity = mapper.convertValue(rs.getBody().getData(), ProvinceAndCity.class);
        return provinceAndCity;
    }

    @Override
    public boolean editMerchantAvatar(MerchantAvatarDto dto) {
        Merchant merchant = new Merchant();
        merchant.setId(dto.getMerchantId());
        merchant.setMerchantAvatar(dto.getUrl());
        merchant.setUpdatedTime(System.currentTimeMillis() / 1000);
        merchantMapper.updateByPrimaryKeySelective(merchant);
        return true;
    }

    @Override
    public boolean editBasicMerchant(EditBasicMerchantDto dto) {
        Merchant merchant = new Merchant();
        BeanUtils.copyProperties(dto, merchant);
        merchant.setId(dto.getMerchantId());
        merchant.setUpdatedTime(System.currentTimeMillis() / 1000);
        merchantMapper.updateByPrimaryKeySelective(merchant);
        return true;
    }

    @Override
    public boolean merchantEnvironment(MerchantEnvironmentDto dto) {
        long currentTime = System.currentTimeMillis() / 1000;
        // 删除之前的照片
        merchantEnvironmentMapper.delImg(dto.getMerchantId(), currentTime);
        if (!dto.getImgs().isEmpty()) {
            // 添加新的照片
            List<MerchantEnvironment> recordList = new ArrayList<>();
            for (String img : dto.getImgs()) {
                MerchantEnvironment merchantEnvironment = new MerchantEnvironment(img, dto.getMerchantId(),
                        currentTime);
                merchantEnvironment.setDeleted(0);
                recordList.add(merchantEnvironment);
            }
            merchantEnvironmentMapper.insertList(recordList);
        }
        return true;
    }

    @Override
    public MerchantDetailInfo getMerchantDetailInfo(Long id, String language) {
        MerchantHomeInfo merchantHomeInfo = null;
        MerchantDetailInfo detailInfo = new MerchantDetailInfo();
        ProvinceAndCity provinceAndCity = null;
        merchantHomeInfo = merchantMapper.getMerchantHome(id, language);
        provinceAndCity = getProvinceAndCity(language, merchantHomeInfo.getStoreAreaId());
        if (provinceAndCity != null) {
            merchantHomeInfo.setCity(provinceAndCity.getCity());
            merchantHomeInfo.setProvince(provinceAndCity.getProvince());
        } else {
            merchantHomeInfo.setCity("");
            merchantHomeInfo.setProvince("");
        }
        List<Integer> countMerchant = merchantMapper.getCountsByMerchantId(id);
        List<KeyValueModel<Long, String>> categoryList = merchantMapper.getCategoryByMerchantId(id, language);
        merchantHomeInfo.setCategory(categoryList);
        detailInfo.setMerchantInfo(merchantHomeInfo);
        detailInfo.setCountConcern(countMerchant.get(0));
        detailInfo.setCountGoods(countMerchant.get(1));
        detailInfo.setCountComment(countMerchant.get(2));
        return detailInfo;
    }

    @Override
    public Map<String, Object> getMerchantGoods(Long merchantId, Integer status, Long categoryId, Integer page,
                                                Integer size, String language) {
        page = GlobalController.checkPage(page, size);
        Integer start = (page - 1) * size;
        List<MerchantGoodsInfo> goodsList = goodsMapper.getGoods(merchantId, status, categoryId, start, size, language);

        List<Long> goodsIds = goodsList.stream().map(goods -> goods.getId()).collect(Collectors.toList());
        Map<Long, Integer> commentCountMap = new HashMap<>(16);
        // Map<Long, KeyValueModel<Long, Integer>> map = new HashMap<>();
        if (goodsIds.size() != 0) {
            // 根据goodsids查群出每个商品的平评论数
            // map = goodsCommentMapper.getCommentCountByGoodIds(goodsIds);
            List<KeyValueModel<Long, Integer>> goodsCommentCountList = goodsCommentMapper
                    .listFindCommentCountByGoodIds(goodsIds);
            commentCountMap = goodsCommentCountList.stream().collect(
                    Collectors.toMap(KeyValueModel<Long, Integer>::getId, KeyValueModel<Long, Integer>::getValue));
        }

        // Map<Long, Integer> commentCountMap =
        // goodsCommentMapper.getCommentCountByGoodIds(goodsIds);
        // 根据goodsids查群出所有的图片
        List<GoodsImg> goodsImgList = goodsImgMapper.getImgByGoodsIds(goodsIds);
        // 把goodsId一样的图片放在一起
        Map<Long, List<GoodsImg>> goodsImgListMap = goodsImgList.stream()
                .collect(Collectors.groupingBy(GoodsImg::getGoodsId));

        for (MerchantGoodsInfo merchantGoodsInfo : goodsList) {
            // 把每个goods的图片加进goods
            if (goodsImgListMap != null && goodsImgListMap.get(merchantGoodsInfo.getId()) != null) {
                // 把当前商品的图片根据type分类
                for (GoodsImg goodsImg : goodsImgListMap.get(merchantGoodsInfo.getId())) {
                    if (goodsImg != null && goodsImg.getType() == 1) { // 图片类型，1展示图片 2详情配图
                        GoodsImgInfo goodsImgInfo = new GoodsImgInfo(goodsImg.getImgUrl(), goodsImg.getVideoUrl());
                        merchantGoodsInfo.getShowImgs().add(goodsImgInfo);
                    } else if (goodsImg != null && goodsImg.getType() == 2) {
                        GoodsImgInfo goodsImgInfo = new GoodsImgInfo(goodsImg.getImgUrl(), goodsImg.getVideoUrl());
                        merchantGoodsInfo.getDetailImgs().add(goodsImgInfo);
                    }
                }
            }
            // 把每个goods的评论数加进goods
            if (commentCountMap != null) {
                Integer count = commentCountMap.get(merchantGoodsInfo.getId());
                if (count != null) {
                    merchantGoodsInfo.setCommentCount(count == null ? 0 : count);
                }
            }
        }
        // 获取merchantId, status, categoryId条件下的商品数量
        Integer count = goodsMapper.getGoodsCount(merchantId, status, categoryId);
        //店铺下的全部小类（修改用）
        Merchant merchant = merchantMapper.selectByPrimaryKey(merchantId);
        List<KeyValueModel<Long, String>> allCategoryList = null;
        if (merchant != null && merchant.getCategoryId() != null) {
            allCategoryList = categoryMapper.findLabelCategoryListByLabelId(merchant.getCategoryId().intValue(), language);
        }
        // 店铺下筛选用的小类（筛选用）
        List<KeyValueModel<Long, String>> categoryList = merchantMapper.getCategoryByMerchantId(merchantId, language);
        Map<String, Object> rs = new HashMap<>();
        rs.put("goods", goodsList);
        rs.put("count", count);
        rs.put("category", categoryList);
        rs.put("allCategoryList", allCategoryList);
        return rs;
    }

    @Override
    public List<MerchantHomeInfo> findHotMerchant(String name, Integer page, Integer label) {
        if (label == null || label <= ConstantValue.GOODS_CATEGORY_ALL) {
            label = null;
        }
        if (null == page || page <= 0) {
            page = 1;
        }
        int start = (page - 1) * ConstantValue.HOME_SEARCH_SHOW_SIZE;
        name = LanguageEnum.getColumnName(name);
        List<MerchantHomeInfo> result = merchantMapper.findHotMerchant(name, label, start, ConstantValue.HOME_SEARCH_SHOW_SIZE);
        return result;
    }

    @Override
    public List<MerchantHomeInfo> findRecommendMerchant(String name, Integer page, Integer label) {
        if (label == null || label <= ConstantValue.GOODS_CATEGORY_ALL) {
            label = null;
        }
        if (null == page || page <= 0) {
            page = 1;
        }
        int start = (page - 1) * ConstantValue.HOME_SEARCH_SHOW_SIZE;
        name = LanguageEnum.getColumnName(name);
        List<MerchantHomeInfo> result = merchantMapper.findRecommendMerchant(name, label, start, ConstantValue.HOME_SEARCH_SHOW_SIZE);
        return result;
    }

    @Override
    public List<MerchantHomeInfo> findNearestMerchant(Integer page, Integer label, Double longitude, Double latitude, String language) {
        List<MerchantHomeInfo> result = new ArrayList<>(16);
        BasicDBObject obQuery = new BasicDBObject();
        if (label != null && label > ConstantValue.GOODS_CATEGORY_ALL) {
            obQuery.append("category_id", label);
        }
        obQuery.put("status", ConstantValue.GOODS_NORMAL_STATUS_CODE);
        obQuery.put("deleted", ConstantValue.DATA_NOT_DELETED);
        List<BasicDBObject> pipeline = new ArrayList<>();
        if (null == page || page <= 0) {
            page = 1;
        }
        Double[] point = new Double[]{longitude, latitude};
        BasicDBObject skipObject = new BasicDBObject("$skip", (page - 1) * ConstantValue.HOME_SEARCH_SHOW_SIZE);
        pipeline.add(skipObject);
        BasicDBObject limitObject = new BasicDBObject("$limit", ConstantValue.HOME_SEARCH_SHOW_SIZE);
        pipeline.add(limitObject);
        AggregateIterable<Document> iterators = merchantDao.findAroundMerchant(ConstantValue.MONGO_MERCHANT, point,
                ConstantValue.HOME_SEARCH_SHOW_DISTANCE, obQuery, pipeline, page * ConstantValue.HOME_SEARCH_SHOW_SIZE);
        MongoCursor<Document> cursor = iterators.iterator();
        while (cursor.hasNext()) {
            Document doc = cursor.next();
            MerchantHomeInfo tempObj = new MerchantHomeInfo();
            tempObj.setId(doc.getLong("_id"));
            tempObj.setMerchantAvatar(doc.getString("merchant_avatar"));
            tempObj.setMerchantName(doc.getString("merchant_name"));
            tempObj.setStoreAdderss(doc.getString("store_adderss"));
            Document document = (Document) doc.get("loc");
            ArrayList<Double> location = (ArrayList<Double>) document.get("coordinates");
            tempObj.setLat(location.get(1).toString());
            tempObj.setLng(location.get(0).toString());
            tempObj.setCategoryId(doc.getLong("category_id"));
            result.add(tempObj);
        }
        if (result.size() > 0) {
            //选择的全部
            List<Long> ids = result.stream().map(e -> e.getCategoryId()).collect(Collectors.toList());
            Map<Long, Category> map = categoryMapper.getCategoryListByIdList(ids);
            for (MerchantHomeInfo info : result) {
//				System.out.println("info " + info == null);
//				System.out.println("map " + map == null);
//				if(info != null) {
//					System.out.println("merchantId：" + info.getId());
//					System.out.println("info.getCategoryId() " + info.getCategoryId());
//					if(info.getCategoryId() != null) {
//						System.out.println("map.get(info.getCategoryId()) " + map.get(info.getCategoryId()));
//					}
//				}
                if (map.get(info.getCategoryId()) != null) {
                    switch (language) {
                        case "name_cn":
                            info.setCategoryName(map.get(info.getCategoryId()).getNameCn());
                            break;
                        case "name_en":
                            info.setCategoryName(map.get(info.getCategoryId()).getNameEn());
                            break;
                        case "name_es":
                            info.setCategoryName(map.get(info.getCategoryId()).getNameEs());
                            break;
                        case "name_pt":
                            info.setCategoryName(map.get(info.getCategoryId()).getNamePt());
                            break;
                        default:
                            info.setCategoryName(map.get(info.getCategoryId()).getNamePt());
                            break;
                    }
                } else {
                    info.setCategoryName("");
                }
            }
        }
        return result;
    }


}
